package com.ruoyi.framework.websocket;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.PChatDetails;
import com.ruoyi.system.domain.POrder;
import com.ruoyi.system.domain.bo.PChatBo;
import com.ruoyi.system.domain.bo.PChatDetailsBo;
import com.ruoyi.system.domain.bo.PChatListBo;
import com.ruoyi.system.domain.vo.PChatDetailsVo;
import com.ruoyi.system.domain.vo.PChatListVo;
import com.ruoyi.system.domain.vo.PChatVo;
import com.ruoyi.system.service.IPChatDetailsService;
import com.ruoyi.system.service.IPChatListService;
import com.ruoyi.system.service.IPChatService;
import com.ruoyi.system.service.IPOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.Semaphore;

/**
 * websocket 消息处理
 *
 * @author ruoyi
 */
@Component
@ServerEndpoint("/websocket/message/{id}/{loid}/{orderid}/{status}")
public class WebSocketServer
{
    /**
     * WebSocketServer 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 默认最多允许同时在线人数100
     */
    public static int socketMaxOnlineCount = 100;

    //记录每个session id发送过快的时间，防止用户恶意刷屏
  //  private static  Map<String, Date> timeLimitMap = new Hashtable<>();

    private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);

    @Resource
    private IPChatService iPChatService = SpringUtils.getBean(IPChatService.class);

    @Resource
    private  IPChatListService iPChatListService = SpringUtils.getBean(IPChatListService.class);

    @Resource
    private  IPChatDetailsService iPChatDetailsService = SpringUtils.getBean(IPChatDetailsService.class);
    @Resource
    private  IPChatListService iIPChatListService = SpringUtils.getBean(IPChatListService.class);
    @Resource
    private IPOrderService ipOrderService = SpringUtils.getBean(IPOrderService.class);







    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("id") String id,@PathParam("loid") String loids,@PathParam("orderid") String orderid,@PathParam("status") int status, Session session) throws Exception
    {
        boolean semaphoreFlag = false;
        // 尝试获取信号量
        semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);
        if (!semaphoreFlag)
        {
            // 未获取到信号量
            LOGGER.error("\n 当前在线人数超过限制数- {}", Optional.of(socketMaxOnlineCount));
            WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数：" + socketMaxOnlineCount);
            session.close();
        }
        else
        {
                WebSocketUsers.put(id, session);
                LOGGER.info("\n 建立连接 - {}", session);
                LOGGER.info("\n 当前人数 - {}", Optional.of(WebSocketUsers.getUsers().size()));

            //检查是否聊天过
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("type","chatInformation");
            PChatListBo bo = new PChatListBo();
            bo.setAnotherId(Long.valueOf(loids));
            bo.setUserId(Long.valueOf(id));
            bo.setStatus(status);
            List<PChatListVo> list = iIPChatListService.queryList(bo);
            List<PChatDetailsVo> pChatDetailsList = new ArrayList<>();
            if(!"undefined".equals(orderid)){
                PChatDetailsBo bos = new PChatDetailsBo();
                bos.setOrderId(orderid);
                pChatDetailsList =  iPChatDetailsService.queryList(bos);
            }
            if(list.size() == 0  && pChatDetailsList.size()== 0){
                jsonObject.put("data","");
            }else{
                if("undefined".equals(orderid)){
                    //查询聊天记录
                    List<PChatDetailsBo> list1 = iPChatDetailsService.pChatDetailsList(list.get(0).getChatId(),0);
                    for(PChatDetailsBo lisat: list1){
                        if(String.valueOf(lisat.getUserId()).equals(id)){
                            lisat.setType(1);
                            lisat.setChatId(","+(list.get(0).getChatId()));
                        }else{
                            lisat.setType(0);
                            lisat.setChatId(","+(list.get(0).getChatId()));
                        }
                    }
                    PChatListVo pChatListVo = new PChatListVo();
                    pChatListVo.setAnotherId(Long.valueOf(loids));
                    pChatListVo.setUserId(Long.valueOf(id));
                    pChatListVo.setChatId(list.get(0).getChatId());
                    List<PChatListVo> listVos =  iIPChatListService.queryList(BeanUtil.toBean(pChatListVo, PChatListBo.class));
                    listVos.get(0).setUnread(Long.valueOf("0"));
                    iIPChatListService.updateByBo(BeanUtil.toBean(listVos.get(0), PChatListBo.class));
                    jsonObject.put("data",list1);
                }else{ //查询订单聊天列表
                    if(pChatDetailsList.size() > 0 ){
                        List<PChatDetailsBo> list1 = iPChatDetailsService.pChatDetailsLists(pChatDetailsList.get(0).getChatId(),0,orderid);
                        for(PChatDetailsBo lisat: list1){
                            if(String.valueOf(lisat.getUserId()).equals(id)){
                                lisat.setType(1);
                            }else{
                                lisat.setType(0);
                            }
                            lisat.setChatId(","+list.get(0).getChatId());
                        }
                        PChatListVo pChatListVo = new PChatListVo();
                        pChatListVo.setAnotherId(Long.valueOf(loids));
                        pChatListVo.setUserId(Long.valueOf(id));
                        pChatListVo.setChatId(pChatDetailsList.get(0).getChatId());
                        List<PChatListVo> listVos =  iIPChatListService.queryList(BeanUtil.toBean(pChatListVo, PChatListBo.class));
                        listVos.get(0).setUnread(Long.valueOf("0"));
                        iIPChatListService.updateByBo(BeanUtil.toBean(listVos.get(0), PChatListBo.class));
                        jsonObject.put("data",list1);
                    }
                }
            }
            WebSocketUsers.sendMessageToUserByText(session, jsonObject.toString());

        }
    }

    /**
     * 连接关闭时处理
     */
    @OnClose
    public void onClose(Session session)
    {
        LOGGER.info("\n 关闭连接 - {}", session);
        // 移除用户
        WebSocketUsers.remove(session);
        // 获取到信号量则需释放
        SemaphoreUtils.release(socketSemaphore);
        String loid = "";
        Set<Map.Entry<String, Session>> entries = WebSocketUsers.getUsers().entrySet();
        for (Map.Entry<String, Session> entry : entries)
        {
            Session value = entry.getValue();
            if (value.equals(session))
            {
                loid =  entry.getKey();
                break;
            }
        }
        RedisUtils.deleteObject("abc:"+loid);
    }

    /**
     * 抛出异常时处理
     */
    @OnError
    public void onError(Session session, Throwable exception) throws Exception
    {
        if (session.isOpen())
        {
            // 关闭连接
            session.close();
        }
        String sessionId = session.getId();
        LOGGER.info("\n 连接异常 - {}", sessionId);
        LOGGER.info("\n 异常信息 - {}", exception);
        // 移出用户
        WebSocketUsers.remove(sessionId);
        // 获取到信号量则需释放
        SemaphoreUtils.release(socketSemaphore);
    }

    /**
     * 服务器接收到客户端消息时调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session)
    {
       // Date timeLimit = DateUtils.addSeconds(new Date(), -2);
        int is_z = 0;
        String loid = ""; //发送者
        Long id = Long.valueOf(0);
        Set<Map.Entry<String, Session>> entries = WebSocketUsers.getUsers().entrySet();
        for (Map.Entry<String, Session> entry : entries)
        {
            Session value = entry.getValue();
            if (value.equals(session))
            {
                loid =  entry.getKey();
                break;
            }
        }
        JSONObject jsonObject = JSONObject.parseObject(message);

        if("HEARTBEAT".equals(jsonObject.get("type"))){ //心跳信息
            WebSocketUsers.sendMessageToUserByText(session, "心跳回复");
        }else{
            String type = jsonObject.getString("type"); //被聊天者
            Map<String, Object> map = (Map<String, Object>) jsonObject.get("data");
            String  status = map.get("status").toString(); //发送端
            String orderId = null;
            List<PChatVo> list = new ArrayList<>();
            //缓存
            String key = type + loid;
            String  str = RedisUtils.getCacheObject(key);
            String keys = loid + type;
            String  strr = RedisUtils.getCacheObject(keys);
            if(!"undefined".equals(map.get("orderid")) && map.get("orderid")!=null){

                orderId = map.get("orderid").toString(); //订单id
                //判断订单聊天是否超时
                POrder pOrder = ipOrderService.queryById(Long.valueOf(orderId));
                Date now = new Date();
                long waitMinutes = DateUtils.differentMinutesByMillisecond(pOrder.getStartTime(), now);
                if(Integer.parseInt(String.valueOf(waitMinutes)) > Integer.parseInt(pOrder.getTimeSize())){
                        JSONObject jsonObjects = new JSONObject();
                        jsonObjects.put("type","error");
                        jsonObjects.put("data","聊天室已过期.");
                        WebSocketUsers.sendMessageToUserByText(session,jsonObjects.toString());
                        return;
                }
                String  orderstr = RedisUtils.getCacheObject(orderId);
                //查询redis是否缓存
                if(orderstr == null){
                    PChatDetailsBo bo = new PChatDetailsBo();
                    bo.setOrderId(orderId);
                    List<PChatDetailsVo> pChatDetailsList =  iPChatDetailsService.queryList(bo);
                    if(pChatDetailsList.size() == 0){
                        //订单第一次聊天创建聊天列表
                        //创建聊天列表
                        PChatBo boa = new PChatBo();
                        boa.setAnotherId(Long.valueOf(loid));
                        boa.setUserId(Long.valueOf(type));
                        id = iPChatService.insertByBo(boa);
                        PChatListBo pChatListBo = new PChatListBo();
                        pChatListBo.setChatId(id);
                        pChatListBo.setAnotherId(Long.valueOf(type));
                        pChatListBo.setUserId(Long.valueOf(loid));
                        pChatListBo.setStatus(1);
                        iPChatListService.insertByBo(pChatListBo);
                        PChatListBo pChatListBos = new PChatListBo();
                        pChatListBos.setChatId(id);
                        pChatListBos.setAnotherId(Long.valueOf(loid));
                        pChatListBos.setUserId(Long.valueOf(type));
                        pChatListBos.setStatus(2);
                        iPChatListService.insertByBo(pChatListBos);
                    }
                    if(id == 0){
                        id = pChatDetailsList.get(0).getChatId();
                    }
                    RedisUtils.setCacheObject(orderId,id, Duration.ofMinutes(-1));
                    str = String.valueOf(id);
                }else{
                    id = Long.valueOf(orderstr);
                }
                //更新被聊天者
                RedisUtils.setCacheObject("a:"+loid,type, Duration.ofMinutes(-1));
            }else{
                if(str == null && strr == null){
                    //检查是否聊天过
                    PChatBo bo = new PChatBo();
                    if("2".equals(status)){
                        bo.setAnotherId(Long.valueOf(loid));
                        bo.setUserId(Long.valueOf(type));
                    }else {
                        bo.setAnotherId(Long.valueOf(type));
                        bo.setUserId(Long.valueOf(loid));
                    }
                    list = iPChatService.queryList(bo);
                    if(list.size() == 0){
                        id = iPChatService.insertByBo(bo);
                        //创建聊天列表
                        PChatListBo pChatListBo = new PChatListBo();
                        pChatListBo.setChatId(id);
                        pChatListBo.setAnotherId(Long.valueOf(type));
                        pChatListBo.setUserId(Long.valueOf(loid));
                        pChatListBo.setStatus(1);
                        iPChatListService.insertByBo(pChatListBo);
                        PChatListBo pChatListBos = new PChatListBo ();
                        pChatListBos.setChatId(id);
                        pChatListBos.setAnotherId(Long.valueOf(loid));
                        pChatListBos.setUserId(Long.valueOf(type));
                        pChatListBos.setStatus(2);
                        iPChatListService.insertByBo(pChatListBos);
                    }
                    if(id == 0){
                        id = list.get(0).getId();
                    }
                    RedisUtils.setCacheObject(key,id, Duration.ofMinutes(-1));
                    RedisUtils.setCacheObject(keys,id, Duration.ofMinutes(-1));
                    str = String.valueOf(id);
                }
                //更新被聊天者
                RedisUtils.setCacheObject("abc:"+loid,type, Duration.ofMinutes(-1));
            }


            //boolean before = timeLimit.before(timeLimitMap.get(session.getId()));
            //if (before) {
            //    JSONObject jsonObjects = new JSONObject();
            //    jsonObjects.put("type","error");
            //    jsonObjects.put("data","请勿刷屏，频繁发送信息");
            //    WebSocketUsers.sendMessageToUserByText(session,jsonObjects.toString());
            //    return;
            //}



            //保存发送的消息
            PChatDetailsBo bos = new PChatDetailsBo();
            if("0".equals(String.valueOf(id))){
                id = list.get(0).getId();
            }
            bos.setChatId(String.valueOf(id));
            bos.setUserId(Long.valueOf(loid));
            if(orderId!=null){
                bos.setOrderId(orderId);
            }
            bos.setContent(map.get("msg").toString());
            bos.setStatus(Integer.parseInt(status));
            PChatDetails pChatDetails = iPChatDetailsService.cancelByParams(Long.valueOf(loid),id,orderId);
            PChatDetails pChatDetaila = iPChatDetailsService.cancelByParams(Long.valueOf(type),id,orderId);
            if(pChatDetails != null){
                //更新最新一条消息
                pChatDetails.setIsLatest(Long.valueOf("0"));
                iPChatDetailsService.updateByBo(BeanUtil.toBean(pChatDetails, PChatDetailsBo.class));
            }
            if(pChatDetaila != null){
                pChatDetaila.setIsLatest(Long.valueOf("0"));
                iPChatDetailsService.updateByBo(BeanUtil.toBean(pChatDetaila, PChatDetailsBo.class));
            }
            bos.setIsLatest(Long.valueOf("1"));
            iPChatDetailsService.insertByBo(bos);
            Set<String> set = WebSocketUsers.getUsers().keySet();
            for(String s : set){
                if(s.equals(type)){
                    map.put("id",loid);
                    map.put("orderId",orderId);
                    jsonObject.put("data",map);
                    session =  WebSocketUsers.getUsers().get(s);
                    WebSocketUsers.sendMessageToUserByText(session, jsonObject.toString());
                    is_z = 1;
                    break;
                }
            }
            if(is_z == 0){
                //不在线新增未读
                PChatListBo bo = new PChatListBo();
                bo.setChatId(Long.valueOf(str));
                bo.setAnotherId(Long.valueOf(loid));
                bo.setUserId(Long.valueOf(type));
                List<PChatListVo> listVos = iPChatListService.queryList(bo);
                listVos.get(0).setUnread((long) (Integer.parseInt(String.valueOf(listVos.get(0).getUnread())) + 1));
                iPChatListService.updateByBo(BeanUtil.toBean(listVos.get(0), PChatListBo.class));
            }else{
                //判断是否在跟当前人聊天
                String  typestr = null;
                if(orderId != null){
                    typestr =  RedisUtils.getCacheObject("a:"+type);
                }else{
                    typestr =  RedisUtils.getCacheObject("abc:"+type);
                }
                //判断被聊天者是否在跟聊天者聊
                if(typestr!=null){
                    if(!typestr.equals(loid)){
                        //如果不是在跟聊天者聊天新增未读
                        PChatListBo bo = new PChatListBo();
                        bo.setChatId(Long.valueOf(str));
                        bo.setAnotherId(Long.valueOf(loid));
                        bo.setUserId(Long.valueOf(type));
                        List<PChatListVo> listVos = iPChatListService.queryList(bo);
                        listVos.get(0).setUnread((long) (Integer.parseInt(String.valueOf(listVos.get(0).getUnread())) + 1));
                        iPChatListService.updateByBo(BeanUtil.toBean(listVos.get(0), PChatListBo.class));
                    }
                }
            }
        }
    }
}
